#define  _CRT_SECURE_NO_WARNINGS
// 下面是我写的链表
// 代码讲解：https://abyssal-oathsworn.blog.csdn.net/article/details/145407013
#include <iostream>
#include <cassert>
using namespace std;
template <class T> struct listNode {
    listNode() : _pPrev(this), _pNext(this) {}
    listNode(const T& val) : _pPrev(nullptr), _pNext(nullptr), _val(val) {}
    void insertBetween(listNode* pPrev, listNode* pNext) {
        _pPrev = pPrev;
        _pNext = pNext;
        pPrev->_pNext = pNext->_pPrev = this;
    }
    listNode<T>* _pPrev;
    listNode<T>* _pNext;
    T _val;
};

template <class T, class Ref, class Ptr> struct listIterator {
    typedef listNode<T>* PNode;
    typedef listIterator<T, Ref, Ptr> Self;
    listIterator(PNode pNode = nullptr) : _pNode(pNode) {}
    listIterator(const Self& l) : _pNode(l._pNode) {}
    Ref operator*() { return _pNode->_val; }
    Ptr operator->() { return &_pNode->_val; }

    Self& operator++() {
        _pNode = _pNode->_pNext;
        return *this;
    }
    Self operator++(int) {
        Self tmp(*this);
        _pNode = _pNode->_pNext;
        return tmp;
    }
    Self& operator--() {
        _pNode = _pNode->_pPrev;
        return *this;
    }
    Self operator--(int) {
        Self tmp(*this);
        _pNode = _pNode->_pPrev;
        return tmp;
    }
    bool operator!=(const Self& l) { return _pNode != l._pNode; }
    bool operator==(const Self& l) { return _pNode == l._pNode; }
    PNode _pNode;
};

template <class T> class list {
    typedef listNode<T> Node;
    typedef Node* PNode;

public:
    typedef listIterator<T, T&, T*> iterator;
    typedef listIterator<T, const T&, const T*> const_iterator;

public:
    list() : _pHead(new Node), _size(0) {}
    list(int n, const T& value = T()) : _pHead(new Node), _size(0) {
        while (n--)
            push_back(value);
    }
    template <class Iterator>
    list(Iterator first, Iterator last) : _pHead(new Node), _size(0) {
        for (auto it = first; it != last; ++it)
            push_back(*it);
    }
    list(const list& l) : _pHead(new Node), _size(0) {
        for (const auto& e : l)
            push_back(e);
    }
    list& operator=(list l) {
        swap(l);
        return *this;
    }
    ~list() {
        clear();
        delete _pHead;
        _pHead = nullptr;
    }

    iterator begin() { return iterator(_pHead->_pNext); }
    iterator end() { return iterator(_pHead); }
    const_iterator begin() const { return const_iterator(_pHead->_pNext); }
    const_iterator end() const { return const_iterator(_pHead); }

    size_t size() const { return _size; }
    bool empty() const { return _pHead->_pNext == _pHead; }

    T& front() {
        assert(!empty());
        return _pHead->_pNext->_val;
    }
    const T& front() const {
        assert(!empty());
        return _pHead->_pNext->_val;
    }
    T& back() {
        assert(!empty());
        return _pHead->_pPrev->_val;
    }
    const T& back() const {
        assert(!empty());
        return _pHead->_pPrev->_val;
    }

    void push_back(const T& val) { insert(end(), val); }
    void pop_back() { erase(--end()); }
    void push_front(const T& val) { insert(begin(), val); }
    void pop_front() { erase(begin()); }
    iterator insert(iterator pos, const T& val) {
        PNode pNewNode = new Node(val);
        pNewNode->insertBetween(pos._pNode->_pPrev, pos._pNode);
        _size++;
        return iterator(pNewNode);
    }
    iterator erase(iterator pos) {
        assert(!empty() && pos != end());
        PNode pPrev = pos._pNode->_pPrev, pNext = pos._pNode->_pNext;
        pPrev->_pNext = pNext;
        pNext->_pPrev = pPrev;
        delete pos._pNode;
        _size--;
        return iterator(pNext);
    }
    void clear() {
        while (!empty())
            erase(begin());
    }
    void swap(list<T>& l) {
        std::swap(_pHead, l._pHead);
        std::swap(_size, l._size);
    }

    //private:
    PNode _pHead;
    size_t _size;
};
///////////////////////////////////////////////////////////////
#include <string>
#include <sstream>
#include <algorithm>
template<class T> void merge(list<T>* l1, list<T>* l2)
{
    list<T> ans;
    list<T>& list1 = *l1, & list2 = *l2;
    auto it1 = list1.begin(), it2 = list2.begin();
    while (it1 != list1.end() && it2 != list2.end()) {
        if (*it1 < *it2) {
            ans.push_back(*it1);
            it1++;
        }
        else if (*it1 > *it2) {
            ans.push_back(*it2);
            it2++;
        }
        else {
            ans.push_back(*it1);
            it1++;
            it2++;
        }
    }
    while (it1 != list1.end()) {
        ans.push_back(*it1);
        it1++;
    }
    while (it2 != list2.end()) {
        ans.push_back(*it2);
        it2++;
    }
    //list2.clear();
    list<T> tmp(ans.begin(), unique(ans.begin(), ans.end()));
    list1 = tmp;
}
template<class T> void print(list<T>* l)
{
    int jug = 0;
    for (auto e : *l)
    {
        if (jug) cout << "->"; jug = 1;
        cout << e;
    }
}
template<class T> void f(T)
{
    list<T>* l1 = new list<T>(), * l2 = new list<T>();
    string line;
    T cur;

    getchar();
    getline(cin, line);
    {
        stringstream ss;
        ss << line;
        while (ss >> cur)
            l1->push_back(cur);
    }

    getline(cin, line);
    {
        stringstream ss;
        ss << line;
        while (ss >> cur)
            l2->push_back(cur);
    }

    print(l1); cout << endl;
    print(l2); cout << endl;
    cout << endl;

    merge(l1, l2);

    print(l1);
}

int main()
{
    int t; cin >> t;
    if (t < 0 || t > 3) cout << "err";
    else if (t == 0)
        f(int());
    else if (t == 1)
        f(double());
    else if (t == 2)
        f(char());
    else if (t == 3)
        f(string());
    return 0;
}
//0
//3 3 5 5 8 8 11 11
//2 2 6 8 8 9 11